package daily_user_handler

import (
	"context"
	"errors"
	"gitee.com/zylvcxq/gotham-utils/event"
	"gitee.com/zylvcxq/gotham-utils/log_util"
	"gitee.com/zylvcxq/gotham-utils/mail"
	"github.com/go-kratos/kratos/v2/log"
	"github.com/google/uuid"
	"github.com/ser163/WordBot/generate"
	command_service "gotham-plan-manage/internal/app/command_service"
	"gotham-plan-manage/internal/app/query_service"
	"gotham-plan-manage/internal/conf"
	"gotham-plan-manage/internal/domain/command"
	"gotham-plan-manage/internal/domain/query"
	"gotham-plan-manage/internal/infra/cache/redis"
	"gotham-plan-manage/pkg/jwt_util"
	"time"
)

/*
   @author:zhongyang
   @date:2023/8/3
   @description:用户日常行为处理链路
*/

const (
	CreatePlan    = "创建计划"
	CreateItem    = "创建待办"
	FinishItem    = "完成待办"
	SetPlanTarget = "设置计划目标"
	FinishPlan    = "完成计划"
)

type Handler interface {
	SetNext(handler Handler)
	Handle(ctx context.Context) error
}
type BaseHandler struct {
	nextHandler Handler
	*command_service.PlanManageCommandService
	*query_service.PlanManageQueryService
	logger *log_util.GothamLogger
}

func NewEntryHandler(commandService *command_service.PlanManageCommandService, queryService *query_service.PlanManageQueryService, logger log.Logger) Handler {
	baseHandler := BaseHandler{
		PlanManageCommandService: commandService,
		PlanManageQueryService:   queryService,
		logger:                   log_util.NewGothamLogger(logger, mail.NewRealMailSender(redis.GetConn())),
	}
	// 组装责任链
	// 目前顺序：创建计划 =》 设置计划目标 =》到期后完成计划 =》创建待办 =》完成待办
	// 后续考虑做成动态责任链灵活扩展
	c1 := &CreatePlanHandler{baseHandler}
	c2 := &SetPlanTargetHandler{baseHandler}
	c3 := &FinishPlanHandler{baseHandler}
	c4 := &CreateItemHandler{baseHandler}
	c5 := &FinishItemHandler{baseHandler}
	c1.SetNext(c2)
	c2.SetNext(c3)
	c3.SetNext(c4)
	c4.SetNext(c5)
	return c1
}

func (b *BaseHandler) SetNext(handler Handler) {
	b.nextHandler = handler
}

// CreatePlanHandler 创建计划处理
type CreatePlanHandler struct {
	BaseHandler
}

func (c *CreatePlanHandler) Handle(ctx context.Context) error {
	plan, err := c.BaseHandler.PlanManageQueryService.GetOngoingPlan(ctx)
	if err != nil {
		c.BaseHandler.logger.Errorf(ctx, "CreatePlanHandler.Handle#1 err:%v", err)
		return err
	}
	if plan.PlanId == "" {
		word, _ := generate.GenRandomWorld(15, "title")
		c.BaseHandler.logger.Infof(ctx, "CreatePlanHandler.Handle 创建计划")
		// 说明没有正在进行的计划,执行创建操作
		err := c.BaseHandler.PlanManageCommandService.CreatePlan(ctx, &command.PlanCreateCommand{
			Name:      word.Word,
			StartDate: time.Now().Format("2006-01-02"),
			EndDate:   time.Now().Add(7 * 24 * time.Hour).Format("2006-01-02"),
		})
		if err != nil {
			return err
		}
		reportUserDailyBehavior(ctx, CreatePlan)
		return nil
	}
	// 不然就继续往下执行
	if c.nextHandler != nil {
		// 把计划id传下去，方便操作
		ctx := context.WithValue(ctx, "plan_id", plan.PlanId)
		ctx = context.WithValue(ctx, "end_date", plan.EndDate)
		return c.nextHandler.Handle(ctx)
	}
	c.BaseHandler.logger.Debugf(ctx, "CreatePlanHandler.Handle 无执行链路")
	return nil
}

// CreateItemHandler 创建待办处理器
type CreateItemHandler struct {
	BaseHandler
}

func (c *CreateItemHandler) Handle(ctx context.Context) error {
	planId, err := getPlanId(ctx)
	if err != nil {
		c.BaseHandler.logger.Errorf(ctx, "CreateItemHandler.Handle#1 err:%v", err)
		return err
	}
	tasks, err := c.PlanManageQueryService.GetOngoingTasks(ctx, &query.GetOngoingTasksQuery{Scope: "today"})
	if err != nil {
		c.BaseHandler.logger.Errorf(ctx, "CreateItemHandler.Handle#2 err:%v", err)
		return err
	}
	if len(tasks) == 0 {
		word, _ := generate.GenRandomWorld(15, "title")
		c.BaseHandler.logger.Infof(ctx, "CreateItemHandler.Handle 创建待办")
		err := c.PlanManageCommandService.CreateTaskItem(ctx, &command.CreateTaskCommand{
			Content:     word.Word,
			ExecuteDate: time.Now().Format("2006-01-02"),
			Level:       4,
			PlanId:      planId,
		})
		if err != nil {
			return err
		}
		reportUserDailyBehavior(ctx, CreateItem)
		return nil
	}
	if c.nextHandler != nil {
		ctx := context.WithValue(ctx, "task_item_id", tasks[0].TaskItemId)
		return c.nextHandler.Handle(ctx)
	}
	c.BaseHandler.logger.Debugf(ctx, "CreateItemHandler.Handle 无执行链路")
	return nil
}

// FinishItemHandler 完成待办处理器
type FinishItemHandler struct {
	BaseHandler
}

func (c *FinishItemHandler) Handle(ctx context.Context) error {
	taskItemId, err := getTaskItemId(ctx)
	if err != nil {
		c.BaseHandler.logger.Errorf(ctx, "FinishItemHandler.Handle#1 err:%v", err)
		return err
	}
	c.BaseHandler.logger.Infof(ctx, "FinishItemHandler.Handle 完成待办")
	err = c.PlanManageCommandService.FinishTaskItem(ctx, &command.FinishTaskItemCommand{TaskItemId: taskItemId})
	if err != nil {
		c.BaseHandler.logger.Errorf(ctx, "FinishItemHandler.Handle#2 err:%v", err)
		return err
	}
	reportUserDailyBehavior(ctx, FinishItem)
	if c.nextHandler != nil {
		return c.nextHandler.Handle(ctx)
	}
	c.BaseHandler.logger.Debugf(ctx, "FinishItemHandler.Handle 无执行链路")
	return nil
}

// FinishPlanHandler 完成计划处理器
type FinishPlanHandler struct {
	BaseHandler
}

func (c *FinishPlanHandler) Handle(ctx context.Context) error {
	endDate, err := getEndDate(ctx)
	if err != nil {
		c.BaseHandler.logger.Errorf(ctx, "FinishPlanHandler.Handle#1 err:%v", err)
		return err
	}
	planId, err := getPlanId(ctx)
	if err != nil {
		c.BaseHandler.logger.Errorf(ctx, "FinishPlanHandler.Handle#2 err:%v", err)
		return err
	}
	// 超出结束时间，需要完成计划
	if time.Now().Format("2006-01-02") > endDate {
		// 生成报告
		report, err := c.PlanManageQueryService.GeneratePlanReport(ctx, &query.GeneratePlanReportQuery{PlanId: planId})
		if err != nil {
			c.BaseHandler.logger.Errorf(ctx, "FinishPlanHandler.Handle#3 err:%v", err)
			return err
		}
		c.BaseHandler.logger.Infof(ctx, "FinishPlanHandler.Handle 完成计划")
		err = c.PlanManageCommandService.SubmitPlanReport(ctx, &command.PlanReportSubmitCommand{
			PlanId:     planId,
			PlanName:   report.PlanName,
			FinishDate: report.FinishDate,
			IsOverTime: report.IsOverTime,
			ExpectDay:  report.ExpectDay,
			RealDay:    report.RealDay,
			TaskTotal:  report.TaskTotal,
		})
		if err != nil {
			return err
		}
		reportUserDailyBehavior(ctx, FinishPlan)
		return nil
	}
	if c.nextHandler != nil {
		return c.nextHandler.Handle(ctx)
	}
	c.BaseHandler.logger.Debugf(ctx, "FinishPlanHandler.Handle 无执行链路")
	return nil
}

// SetPlanTargetHandler 设置计划目标处理器
type SetPlanTargetHandler struct {
	BaseHandler
}

func (c *SetPlanTargetHandler) Handle(ctx context.Context) error {
	// 查询目标是否已经设置
	planId, err := getPlanId(ctx)
	if err != nil {
		c.BaseHandler.logger.Errorf(ctx, "SetPlanTargetHandler.Handle#1 err:%v", err)
		return err
	}
	detail, err := c.BaseHandler.FindPlanDetail(ctx, &query.GetPlanDetailQuery{PlanId: planId})
	if err != nil {
		c.BaseHandler.logger.Errorf(ctx, "SetPlanTargetHandler.Handle#2 err:%v", err)
		return err
	}
	if detail.Target == "暂无设置目标" {
		//需要进行设置
		c.BaseHandler.logger.Infof(ctx, "SetPlanTargetHandler.Handle 编辑计划目标")
		err := c.BaseHandler.PlanManageCommandService.EditTarget(ctx, &command.TargetEditCommand{
			PlanID: planId,
			Target: "努力赚钱",
		})
		if err != nil {
			return err
		}
		reportUserDailyBehavior(ctx, SetPlanTarget)
		return nil
	}
	if c.nextHandler != nil {
		return c.nextHandler.Handle(ctx)
	}
	c.BaseHandler.logger.Debugf(ctx, "SetPlanTargetHandler.Handle 无执行链路")
	return nil
}

func getPlanId(ctx context.Context) (string, error) {
	planId, ok := ctx.Value("plan_id").(string)
	if !ok {
		return "", errors.New("流程异常，未找到对应的计划id")
	}
	return planId, nil
}

func getTaskItemId(ctx context.Context) (string, error) {
	taskItemId, ok := ctx.Value("task_item_id").(string)
	if !ok {
		return "", errors.New("流程异常，未找到对应的待办id")
	}
	return taskItemId, nil
}

func getEndDate(ctx context.Context) (string, error) {
	endDate, ok := ctx.Value("end_date").(string)
	if !ok {
		return "", errors.New("流程异常，未找到对应计划结束时间")
	}
	return endDate, nil
}

// 上报用户行为事件
func reportUserDailyBehavior(ctx context.Context, behavior string) {
	userBehavior := map[string]string{
		"user_id":  jwt_util.GetUserId(ctx),
		"behavior": behavior,
	}
	_, _ = conf.EventServer.Publish(ctx, &event.Message{
		Id:         uuid.New().String(),
		Topic:      "gotham-plan:report-daily",
		RoutingKey: "gotham-plan:report-daily",
		Body:       userBehavior,
	})
}
